package org.codesamples.springframework.isolation.propagation.levels;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.codesamples.springframework.models.Item;
import org.codesamples.springframework.models.Order;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

@Service
public class IsolationDefault {

	@PersistenceContext
	private EntityManager entityManager;
	
	@Transactional
	public void cleanRecords() {
		entityManager.createQuery("delete from Item").executeUpdate();
		entityManager.createQuery("delete from Order").executeUpdate();		
	}
	
	@Transactional(readOnly=true)
	public long[] getNoOfRecords() {
		long[] num = new long[] {0,0};
		
		num[0] = (Long) entityManager.createQuery("select count(*) from Item").getSingleResult();
		num[1] = (Long) entityManager.createQuery("select count(*) from Order").getSingleResult();
		return num;	
	}
	
	/**
	 * This method should save and return the id of {@link Order} entity
	 * @return id of entity {@link Order} which is saved.
	 */
	@Transactional
	public Long saveAndGet() {
		Order order = new Order();
		order.getItems().add(new Item());
		entityManager.persist(order);
		
		return order.getId();
	}
	
	/**
	 * Should return null as that function is not transactional
	 * @return NULL
	 */
	public Long saveAndGetNoTransaction() {
		Order order = new Order();
		order.getItems().add(new Item());
		entityManager.persist(order);
		
		// below line will return null as this function is not transactional
		return order.getId();
	}
	
	/**
	 * This method should save and return the id of {@link Order} entity
	 * Propagation.REQUIRED : Support a current transaction, create a new one if none exists.
	 * @return id of entity {@link Order} which is saved.
	 */
	@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
	public Long testPersistAndGet_default_required() {
		
		Order order = new Order();
		order.getItems().add(new Item());
		entityManager.persist(order);		
		
		return order.getId();		
	}
	
	/**
	 * This method should save and return the id of {@link Order} entity
	 * Propagation.REQUIRES_NEW : Create a new transaction, suspend the current transaction if one exists.
	 * @return id of entity {@link Order} which is saved
	 */
	@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRES_NEW)
	public Long testPersistAndGet_default_required_new() {
		
		Order order = saveOrder_testPersistAndGet_default_required_new();
		Item item = new Item();
		item.setOrder(order);
		
		entityManager.persist(order);
		return order.getId();
	}
	
	@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
	private Order saveOrder_testPersistAndGet_default_required_new() {
		//System.out.println("Is new transaction :: " + TransactionAspectSupport.currentTransactionStatus().isNewTransaction());
		
		Order order = new Order();		
		entityManager.persist(order);
		
		if(order.getId() >= 1) {
			throw new RuntimeException("Should roll back the order record");
		}
		
		return order;
	}
}
